package container

import (
	"com.yy.api/common/logger"
	"com.yy.api/common/pojo/dto"
	types "com.yy.api/common/pojo/models"
	cP "com.yy.api/common/pojo/param/container"
	imP "com.yy.api/common/pojo/param/image"
	"com.yy.api/server/utils"
)

var gm = NewGpuManager([]int{0, 1, 2, 3, 4, 5, 6, 7})

type CreateInstanceHelper struct {
	portMappingsParam []types.PortMapping
	hostPortList      []string
	gpuIdsParam       []int
}

func NewCreateInstanceHelper(portMappingsOpt string, gpuNum int) (*CreateInstanceHelper, bool) {
	var result CreateInstanceHelper
	portMappings := cP.ToParamPortMappings(portMappingsOpt)
	hostPortList := getHostPortListFromPortMappings(portMappings)
	//if !isHostPortAvailable(hostPortList) {
	//	return &result, false
	//}
	gpuIds, ok := gm.IsAvailable(gpuNum)
	if !ok {
		return &result, false
	}
	//logger.Default.Infof("portMappings:%v,hostPortList:%v,gpuIdsParam:", portMappings, hostPortList, gpuIds)
	return &CreateInstanceHelper{
		portMappingsParam: portMappings,
		hostPortList:      hostPortList,
		gpuIdsParam:       gpuIds,
	}, true
}
func (h *CreateInstanceHelper) GetHostPortList() []string {
	return h.hostPortList
}
func (h *CreateInstanceHelper) GetPortMappingsParam() []types.PortMapping {
	return h.portMappingsParam
}
func (h *CreateInstanceHelper) GetGpuIdsParam() []int { return h.gpuIdsParam }
func (h *CreateInstanceHelper) AcquireGpus() {
	gm.Acquire(h.gpuIdsParam)
}

//func isHostPortAvailable(hostPortList []string) bool {
//	if err := checkUsedPorts(hostPortList); err != nil {
//		logger.Default.Errorf("host port is occupied：%v", err)
//		return false
//	}
//	return true
//}
//func IsImageAvailable(rowImageOption string) bool {
//	if err := checkLocalImage(rowImageOption); err != nil {
//		logger.Default.Errorf("local image not found, try pulling...：%v", err)
//		return false
//	}
//	return true
//}

func PullImage(rowImageParam string) bool {
	if err := agentClient.PullImage(imP.AssemblePullImageParam(rowImageParam)); err != nil {
		logger.Default.Errorf("pull image %v error：%v", rowImageParam, err)
		return false
	}
	return true
}

//func PersistImageInfoToDB(rowImage string) {
//	if err := imageMapper.Create(models.NewImageBasic(rowImage)); err != nil {
//		logger.Default.Errorf("persist image %v info error：%v", rowImage, err)
//	}
//	addRowImageToRedisList(rowImage)
//}

func CreateContainer(rowImageParam string, portMappingsParam []types.PortMapping, gpuIds []int, name string, userId string) (string, bool) {
	var createContainerDto dto.CreateContainerDto
	displayId, ok := utils.GenerateDisplayID()
	if !ok {
		return "", false
	}
	param := cP.AssembleCreateContainerParam(rowImageParam, portMappingsParam, gpuIds, name, userId, displayId)
	err := agentClient.CreateContainer(param, &createContainerDto)
	if err != nil {
		logger.Default.Errorf("%v", err)
		return "", false
	}
	return createContainerDto.ID, true
}

func StartContainer(containerId string) bool {
	if err := agentClient.StartContainer(containerId); err != nil {
		return false
	}
	return true
}

func InspectContainer(containerId string) (dto.InspectContainerDataDto, bool) {
	var reslt dto.InspectContainerDataDto
	if err := agentClient.InspectContainer(containerId, &reslt); err != nil {
		return reslt, false
	}
	return reslt, true
}

//func PersistContainerInfoToDB(userId string, hostPortList []string, portMappingsParam []types.PortMapping, containerId string) {
//	if err := containerMapper.Create(models.NewContainerBasic(containerId, portMappingsParam, userId)); err != nil {
//		logger.Default.Errorf("%v", err)
//	}
//	addUsedHostPortToRedisList(hostPortList)
//}

func getHostPortListFromPortMappings(portMappings []types.PortMapping) []string {
	var hostPortList []string
	for _, portMapping := range portMappings {
		hostPortList = append(hostPortList, portMapping.HostPort)
	}
	return hostPortList
}

// ==========================
func HasContainer(containerIdOrNameOpt string) (bool, bool) {
	logger.Default.Infof("HasContainer: %v", containerIdOrNameOpt)
	var reslt dto.HasContainerDto
	if err := agentClient.HasContainer(cP.AssembleHasContainerParam(containerIdOrNameOpt), &reslt); err != nil {
		logger.Default.Errorf("%v", err)
		return false, false
	}
	return bool(reslt), true
}

// ===========================
func ReleaseContainer(containerIdOrNameOpt string) (dto.ReleaseContainerDto, bool) {
	var reslt dto.ReleaseContainerDto
	if err := agentClient.ReleaseContainer(cP.AssembleReleaseContainerParam(containerIdOrNameOpt), &reslt); err != nil {
		logger.Default.Errorf("%v", err)
		return reslt, false
	}
	return reslt, true
}

// ==========================
func ContainerList(userId string, displayId string, status []string) (dto.ListContainersDto, bool) {
	return queryContainerList(userId, displayId, status, "", []int{}, []string{})
}

// 容器状态监测模块
// 容器创建信息管理模块
// =======================
// toDo what is healthCheck?
func HealthCheckContainer(containerIdOrNameOpt string) (dto.HealthCheckContainerDto, bool) {
	var reslt dto.HealthCheckContainerDto
	if err := agentClient.HealthCheckContainer(cP.AssembleHealthCheckContainerParam(containerIdOrNameOpt), &reslt); err != nil {
		logger.Default.Errorf("%v", err)
		return reslt, false
	}
	return reslt, true
}

// --------------------------------
func queryContainerList(userId string, displayId string, status []string, name string, gpuIds []int, hostPorts []string) (dto.ListContainersDto, bool) {
	var reslt dto.ListContainersDto
	options := cP.NewListContainerParam()
	if userId != "" {
		options.UserId = userId
	}
	if displayId != "" {
		options.DisplayId = displayId
	}
	if name != "" {
		options.Name = name
	}
	if len(status) > 0 {
		options.Status = status
	}
	if len(gpuIds) > 0 {
		options.GpuIds = gpuIds
	}
	if len(hostPorts) > 0 {
		options.HostPorts = hostPorts
	}

	if err := agentClient.ListContainers(*options, &reslt); err != nil {
		logger.Default.Errorf("%v", err)
		return reslt, false
	}
	return reslt, true
}
